<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="../css/main.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/highlight.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/print.css" media="print" rel="stylesheet" type="text/css" />
<title>第11章 - Ajaxの統合</title>
</head>

<body>
<div class="navigation">

<table width="100%">
<tr>
<td width="40%" align="left"><a href="10-Forms.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="12-Caching.html">次の章</a></td>
</tr>
</table>
<hr/>
</div>

<div>
<a name="chapter.11.ajax.integration" id="chapter.11.ajax.integration"></a><h1>第11章 - Ajaxの統合</h1>

<p>クライアントサイド上でのインタラクション、複雑な視覚効果、非同期通信はWeb 2.0のアプリケーションにおいて共通の機能です。JavaScriptを必要とするこれらの機能は、コードを手書きするのはやっかいでデバッグに時間がかかることはよくあります。幸いにして、symfonyはヘルパーの完全なセットをともなうテンプレート内部のJavaScriptの多くの共通部分を自動化します。一行のJavaScriptのコードがなくても多くのクライアントサイドのふるまいを実現できます。開発者は実現したい効果だけに集中していればよく、symfonyが複雑な構文と互換性問題を処理します。</p>

<p>この章ではクライアントサイドのスクリプトを書く作業を円滑にするためにsymfonyによって提供されたツールについて説明します:</p>

<ul>
<li>基本的なJavaScriptヘルパーは、DOM(Document Object Model)要素を更新するもしくはリンクでスクリプトを起動させるために標準規格に準拠している<code>&lt;script&gt;</code>タグを出力します。</li>
<li>Prototypeはsymfonyに統合されたJavaScriptのライブラリです。これはJavaScriptのコアに新しい関数とメソッドを追加することでクライアントサイドのスクリプト開発を加速します。</li>
<li>Ajaxヘルパーによってユーザーはリンクをクリックする、フォームを投稿する、もしくはフォーム要素を修正することでページのいくつかの部分を更新できるようになります。</li>
<li>これらのヘルパーの多くのオプションは、とりわけコールバック関数を利用することで、よりすばらしい柔軟性とパワーも提供します。</li>
<li>script.aculo.usもsymfonyに統合された別のJavaScriptのライブラリです。script.aculo.usはインターフェイスとユーザーエクスペリエンスを強化する動的な視覚効果を追加します。</li>
<li>JSON(JavaScript Object Notation)はサーバーとクライアントスクリプトのあいだでコミュニケーションを行うために使われる標準規格です。</li>
<li>前述のすべての要素を結びつけるクライアントサイドのインタラクションはsymfonyのアプリケーションで実現可能です。オートコンプリート、ドラッグドロップ、ソート可能なリスト、編集可能なテキストはPHPコードの1行、symfonyのヘルパーへの呼び出し、ですべて実装できます。</li>
</ul>

<div class="toc">
<dl>
<dt><a href="#basic.javascript.helpers">11.1. 基本的なJavaScriptヘルパー</a></dt>
<dd><dl>
<dt><a href="#javascript.in.templates">11.1.1. テンプレート内のJavaScript</a></dt>
<dt><a href="#updating.a.dom.element">11.1.2. DOM要素を更新する</a></dt>
<dt><a href="#graceful.degradation">11.1.3. グレイスフルデグラデーション(Graceful Degradation)</a></dt>
</dl></dd>
<dt><a href="#prototype">11.2. Prototype</a></dt>
<dt><a href="#ajax.helpers">11.3. Ajaxヘルパー</a></dt>
<dd><dl>
<dt><a href="#ajax.link">11.3.1. Ajaxのリンク</a></dt>
<dt><a href="#ajaxdriven.forms">11.3.2. Ajax駆動のフォーム</a></dt>
<dt><a href="#periodically.calling.remote.functions">11.3.3. 定期的にリモート関数を呼び出す</a></dt>
</dl></dd>
<dt><a href="#remote.call.parameters">11.4. リモート呼び出しパラメーター</a></dt>
<dd><dl>
<dt><a href="#updating.distinct.elements.according.to.the.response.status">11.4.1. レスポンスの状態にしたがって異なる要素を更新する</a></dt>
<dt><a href="#updating.an.element.according.to.position">11.4.2. 位置にしたがって要素を更新する</a></dt>
<dt><a href="#updating.an.element.according.to.a.condition">11.4.3. 条件にしたがって要素を更新する</a></dt>
<dt><a href="#determining.the.ajax.request.method">11.4.4. Ajaxのリクエストメソッドを決定する</a></dt>
<dt><a href="#authorizing.script.execution">11.4.5. スクリプトの実行を許可する</a></dt>
<dt><a href="#creating.callbacks">11.4.6. コールバック機能を作成する</a></dt>
</dl></dd>
<dt><a href="#creating.visual.effects">11.5. 視覚効果を作成する</a></dt>
<dt><a href="#json">11.6. JSON</a></dt>
<dt><a href="#performing.complex.interactions.with.ajax">11.7. 複雑なインタラクションをAjaxで実行する</a></dt>
<dd><dl>
<dt><a href="#autocompletion">11.7.1. オートコンプリート</a></dt>
<dt><a href="#draganddrop">11.7.2. ドラッグアンドドロップ</a></dt>
<dt><a href="#sortable.lists">11.7.3. ソート可能なリスト</a></dt>
<dt><a href="#edit.in.place">11.7.4. その場で編集する</a></dt>
</dl></dd>
<dt><a href="#summary">11.8. まとめ</a></dt>
</dl>
</div>
<a name="basic.javascript.helpers" id="basic.javascript.helpers"></a><h2>基本的なJavaScriptヘルパー</h2>

<p>JavaScriptはクロスブラウザーの互換性が欠如していたため、プロフェッショナルなWebアプリケーションで実際に使うものはほとんどないと長い間見なされてきました。今日において、互換性の問題は(ほとんど)解決され、いくつかの頑強なライブラリによって、膨大な行数のコーディングと膨大な時間のデバッグを行わなくてもJavaScriptで複雑なインタラクションをプログラミングできます。もっとも人気のある先進技術はAjax(asynchronous JavaScript and XML)と呼ばれます。これはこの章の"Ajaxヘルパー"のセクションで説明します。</p>

<p>逆説的にも、この章ではjavaScriptのコードはほんのわずかしか見ません。symfonyがクライアントサイドのスクリプティングへの独自の方法を持つからです: symfonyはJavaScriptのふるまいをヘルパーにまとめて抽象化するので、テンプレートはJavaScriptのコードをまったく表示せずに終わります。開発者のために、ふるまいをページの要素に追加するにはPHPのコードが1行必要ですが、このヘルパー呼び出しがJavaScriptのコードの出力を行い、生成されたレスポンスを検査すると、すべてがカプセル化された複雑性を持つことがあきらかになります。ヘルパーが、ブラウザーの一貫性、複雑な制限のある事例、拡張性などを扱うので、これらが含むJavaScriptコードの総量が極めて重要になる可能性があります。それゆえ、この章はJavaScriptで開発するために使う効果を実現するためのJavaScriptの使いかたをお教えします。</p>

<p><code>Javascript</code>ヘルパーグループの使用を宣言しているのであれば、ここで説明されるすべてのヘルパーは、テンプレートのなかで利用できます。</p>

<pre class="php"><span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'Javascript'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>すぐに学ぶように、これらのヘルパーのなかにはHTMLのコードやJavaScriptのコードを出力するものがあります。</p>

<a name="javascript.in.templates" id="javascript.in.templates"></a><h3>テンプレート内のJavaScript</h3>

<p>XHTMLにおいて、JavaScriptのコードブロックはCDATA宣言で囲まなければなりません。しかし、複数のJavaScriptのコードブロックを必要とするページを書く作業はすぐに退屈になります。symfonyが文字列をXHTML準拠の<code>&lt;script&gt;</code>タグに変換する<code>javascript_tag()</code>ヘルパーを提供するのはそういうわけです。リスト11-1はこのヘルパーの使いかたのお手本を示しています。</p>

<p>リスト11-1 - <code>javascript_tag()</code>ヘルパーによるJavaScriptの挿入</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_tag<span class="br0">&#40;</span><span class="st0">&quot;
  function foobar()
  {
  ...
  }
&quot;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;script type=&quot;text/javascript&quot;&gt;
    //&lt;![CDATA[
      function foobar()
      {
        ...
      }
    //]]&gt;
    &lt;/script&gt;</pre>

<p>しかし、コードブロックよりも、JavaScriptのもっとも共通の使いかたは、特定のスクリプトを起動させるハイパーリンクのなかにあります。リスト11-2で示されるように、<code>link_to_function()</code>ヘルパーはまさにこれを行います。</p>

<p>リスト11-2 - JavaScriptを<code>link_to_function()</code>ヘルパーをともなうリンクで発動させる</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_function<span class="br0">&#40;</span><span class="st_h">'クリックしてください！'</span><span class="sy0">,</span> <span class="st0">&quot;alert('foobar')&quot;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;#&quot; onClick=&quot;alert('foobar'); return none;&quot;&gt;クリックしてください！&lt;/a&gt;</pre>

<p><code>link_to()</code>ヘルパーと同じように、オプションを3番目の引数の<code>&lt;a&gt;</code>タグに追加できます。</p>

<blockquote class="note"><p>
  <code>link_to()</code>ヘルパーが<code>button_to()</code>の兄弟を持つのと同様に、<code>button_to_function()</code>ヘルパーを呼び出すことでボタン(<code>&lt;input type="button"&gt;</code>)からJavaScriptを発動させることができます。そしてクリック可能なイメージが望ましい場合、<code>link_to_function(image_tag('myimage'), "alert('foobar')")</code>を呼び出します。</p>
</blockquote>

<a name="updating.a.dom.element" id="updating.a.dom.element"></a><h3>DOM要素を更新する</h3>

<p>動的なインターフェイスにおける共通のタスクの1つはページの要素の更新です。通常書くコードはリスト11-3で示されるようなものです。</p>

<p>リスト11-3 - JavaScriptの要素を更新する</p>

<pre class="php">&lt;div id=&quot;indicator&quot;&gt;データ処理の開始&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_tag<span class="br0">&#40;</span><span class="st0">&quot;
  document.getElementById(&quot;</span>indicator<span class="st0">&quot;).innerHTML =
    &quot;</span><span class="sy0">&lt;</span>strong<span class="sy0">&gt;</span>データ処理の完了<span class="sy0">&lt;/</span>strong<span class="sy0">&gt;</span><span class="st0">&quot;;
&quot;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>この目的のために、symfonyはHTMLではなくJavaScriptを生み出すヘルパーを提供します。このヘルパーは<code>update_element_function()</code>と呼ばれます。リスト11-4は使いかたを示しています。</p>

<p>リスト11-4 - JavaScriptの要素を<code>update_element_function()</code>ヘルパーで更新する</p>

<pre class="php">&lt;div id=&quot;indicator&quot;&gt;データ処理の開始&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_tag<span class="br0">&#40;</span>
  update_element_function<span class="br0">&#40;</span><span class="st_h">'indicator'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'content'</span>  <span class="sy0">=&gt;</span> <span class="st0">&quot;&lt;strong&gt;データ処理の終了&lt;/strong&gt;&quot;</span><span class="sy0">,</span>
  <span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>少なくとも実際のJavaScriptのコードと同じぐらいの長さがあるので、なぜこのヘルパーがとりわけ便利なのかに戸惑っているかもしれません。本当の問題は読みやすさです。たとえば、要素の前あとで内容を挿入したい場合、要素を更新する代わりに除去したい場合、もしくはある種の条件にしたがって何も行いたくない場合があります。そのような場合において、JavaScriptのコードはやや散乱しますが、リスト11-5で示されるように、<code>update_element_function()</code>はテンプレートをとても読みやすいように維持します。</p>

<p>リスト11-5 - <code>update_element_function()</code>ヘルパーのオプション</p>

<pre class="php"><span class="co1">// 'indicator'要素の直後に内容を差し込む</span>
update_element_function<span class="br0">&#40;</span><span class="st_h">'indicator'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'position'</span> <span class="sy0">=&gt;</span> <span class="st_h">'after'</span><span class="sy0">,</span>
  <span class="st_h">'content'</span>  <span class="sy0">=&gt;</span> <span class="st0">&quot;&lt;strong&gt;データの章が完了&lt;/strong&gt;&quot;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="co1">// $conditionがtrueの場合のみ、'indicator'の前の要素を除去する</span>
update_element_function<span class="br0">&#40;</span><span class="st_h">'indicator'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'action'</span>   <span class="sy0">=&gt;</span> <span class="re0">$condition</span> ? <span class="st_h">'remove'</span> <span class="sy0">:</span> <span class="st_h">'empty'</span><span class="sy0">,</span>
  <span class="st_h">'position'</span> <span class="sy0">=&gt;</span> <span class="st_h">'before'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span></pre>

<p>ヘルパーによってテンプレートはJavaScriptのコードよりも理解しやすくなります。そして似たようなふるまいに対して単独の構文があります。これはヘルパーの名前がとても長い理由でもあります: 追加コメントなしで、コードの名前そのものが説明になります。</p>

<a name="graceful.degradation" id="graceful.degradation"></a><h3>グレイスフルデグラデーション(Graceful Degradation)</h3>

<p><code>&lt;noscript&gt;</code>タグによってJavaScriptのサポートを持たないブラウザーが表示するHTMLコードを指定できます。symfonyはまったく逆のことを行うヘルパーでこれを補完します: symfonyがコードを保証するので、JavaScriptを実際にサポートするブラウザーだけがコードを実行します。リスト11-6で示されるように、<code>if_javascript()</code>と<code>end_if_javascript()</code>ヘルパーはグレースフルデグラデーション(graceful degradation)をサポートする(訳注：フォールトトレラントシステムとも言い換えできる)アプリケーションの作成を円滑にします。</p>

<p>リスト11-6 - グレースフルデグラデーションを可能にする<code>if_javascript()</code>ヘルパーを使う</p>

<pre class="php"><span class="kw2">&lt;?php</span> if_javascript<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
  &lt;p&gt;JavaScriptは有効です。&lt;/p&gt;
<span class="kw2">&lt;?php</span> end_if_javascript<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
&nbsp;
&lt;noscript&gt;
  &lt;p&gt;JavaScriptは有効ではありません。&lt;/p&gt;
&lt;/noscript&gt;</pre>

<blockquote class="note"><p>
  <code>if_javascript()</code>と<code>end_if_javascript()</code>ヘルパーを呼び出すときに<code>echo</code>を含む必要はありません。</p>
</blockquote>

<a name="prototype" id="prototype"></a><h2>Prototype</h2>

<p>Prototypeは偉大なJavaScriptのライブラリです。クライアントスクリプト言語の可能性を広げ、いつも夢見ているけれど見つからない関数を追加し、DOMを操作する新しいメカニズムを提供します。プロジェクトのWebサイトは <a href="http://prototypejs.org/">http://prototypejs.org/</a>です。</p>

<p>Prototypeのファイルはsymfonyのフレームワークに搭載されており、すべての新しいsymfonyのプロジェクトの<code>web/sf/prototype</code>ディレクトリにおいて、アクセスできます。このことはつぎのコードをアクションに追加することでPrototypeを利用できるようになることを意味します:</p>

<pre class="php"><span class="re0">$prototypeDir</span> <span class="sy0">=</span> sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'sf_prototype_web_dir'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addJavascript</span><span class="br0">&#40;</span><span class="re0">$prototypeDir</span><span class="sy0">.</span><span class="st_h">'/js/prototype'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>もしくはつぎのコードを<code>view.yml</code>ファイルに追加することでも利用できます:</p>

<pre><code>all:
  javascripts: [%SF_PROTOTYPE_WEB_DIR%/js/prototype]
</code></pre>

<blockquote class="note"><p>
  つぎのセクションで説明するsymfonyのAjaxヘルパーはPrototypeに依存しているので、Prototypeのライブラリの1つを使い始めると同時にPrototypeは自動的にインクルードされます。これはテンプレートが<code>_remote</code>ヘルパーを呼び出す場合、PrototypeのJavaScriptをレスポンスに手動で追加する必要がないことを意味します。</p>
</blockquote>

<p>いったんPrototypeのライブラリがロードされると、JavaScriptのコアに追加されるすべての新しい関数を利用できます。この本の目的はこれらすべてを説明することではないのですが、Web上でPrototypeについてつぎのWebサイトのようなよいドキュメントが見つかります:</p>

<ul>
<li>Particletree: <a href="http://particletree.com/features/quick-guide-to-prototype/">http://particletree.com/features/quick-guide-to-prototype/</a></li>
<li>Sergio Pereira: <a href="http://www.sergiopereira.com/articles/prototype.js.html">http://www.sergiopereira.com/articles/prototype.js.html</a></li>
<li>Script.aculo.us: <a href="http://wiki.script.aculo.us/scriptaculous/show/Prototype">http://wiki.script.aculo.us/scriptaculous/show/Prototype</a></li>
</ul>

<p>JavaScriptに追加されるPrototypeの関数の1つはドル関数の<code>$()</code>です。基本的に、この関数は<code>document.getElementById()</code>へのシンプルなショートカットですが、もう少し強力です。この使いかたの例に関してはリスト11-7をご覧ください。</p>

<p>リスト11-7 - JavaScriptでIDによって要素を取得する<code>$()</code>関数を使う</p>

<pre class="php">node <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="st_h">'elementID'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="co1">// つぎのコードと同じ</span>
node <span class="sy0">=</span> document<span class="sy0">.</span>getElementById<span class="br0">&#40;</span><span class="st_h">'elementID'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="co1">// 一度に複数の要素を取得することも可能で</span>
<span class="co1">// この場合、結果はDOM要素の配列である</span>
nodes <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="st_h">'firstDiv'</span><span class="sy0">,</span> <span class="st_h">'secondDiv'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>PrototypeはJavaScriptのコアが本当に欠如する関数を提供します。たとえば、引数として渡されるクラスを持つすべてのDOM要素の配列を返す関数です:</p>

<pre class="php">nodes <span class="sy0">=</span> document<span class="sy0">.</span>getElementByClassName<span class="br0">&#40;</span><span class="st_h">'myclass'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>しかしながら、これはほとんど使わないでしょう。Prototypeが二重ドル、<code>$$()</code>と呼ばれるもっと強力な関数を提供するからです。この関数はCSSセレクタに基づいてDOM要素の配列を返します。ですので以前の呼び出しをつぎのようにも書けます:</p>

<pre class="php">nodes <span class="sy0">=</span> $$<span class="br0">&#40;</span><span class="st_h">'.myclass'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>CSSセレクタの力のおかげで、クラスとIDでDOMを解析できるので、親子関係と前後関係が以前のXPathの表記で行うよりもはるかに簡単です。これらすべてを結びつける複雑なセレクタで要素にアクセスすることもできます:</p>

<pre class="php">nodes <span class="sy0">=</span> $$<span class="br0">&#40;</span><span class="st_h">'body div#main ul li.last img &gt; span.legend'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>Prototypeによって提供された構文強化の例の最後の1つはeach配列イテレータです。PHPと同等の簡潔さを提供します。匿名関数とクロージャを定義する機能をJavaScriptに追加します。JavaScriptを手作業で実装する場合に多く使います。</p>

<pre class="php"><span class="kw2">var</span> vegetables <span class="sy0">=</span> <span class="br0">&#91;</span><span class="st_h">'Carrots'</span><span class="sy0">,</span> <span class="st_h">'Lettuce'</span><span class="sy0">,</span> <span class="st_h">'Garlic'</span><span class="br0">&#93;</span><span class="sy0">;</span>
vegetables<span class="sy0">.</span><span class="kw3">each</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span>food<span class="br0">&#41;</span> <span class="br0">&#123;</span> alert<span class="br0">&#40;</span><span class="st_h">'I love '</span> <span class="sy0">+</span> food<span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>Prototypeを使うJavaScriptのプログラミングは手作業で行うよりはるかに面白く、このライブラリはsymfonyの一部でもあるので、関連ドキュメントを読むには数分しかかかりません。</p>

<a name="ajax.helpers" id="ajax.helpers"></a><h2>Ajaxヘルパー</h2>

<p>ページの要素を更新したい場合、リスト11-5のようにJavaScriptではなくサーバーによって実行されるPHPのスクリプトで行う場合にはどうしたらよいでしょうか？これによってサーバーのレスポンスにしたがってページの部分を変更する機会が提供されます。リスト11-8で示されるように、<code>remote_function()</code>ヘルパーはまさにこれを行います。</p>

<p>リスト11-8 - <code>remote_function()</code>ヘルパーを使う</p>

<pre class="php">&lt;div id=&quot;myzone&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_tag<span class="br0">&#40;</span>
  remote_function<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>  <span class="sy0">=&gt;</span> <span class="st_h">'myzone'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>     <span class="sy0">=&gt;</span> <span class="st_h">'mymodule/myaction'</span><span class="sy0">,</span>
  <span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<blockquote class="note"><p>
  通常の<code>url_for()</code>のように、<code>url</code>パラメーターは内部のURI(<code>module/action?key1=value1&amp;...</code>)もしくはルーティングルール名のどちらかを含みます。</p>
</blockquote>

<p>呼び出されたとき、このスクリプトは<code>mymodule/myaction</code>アクションのリクエストのレスポンスによってidがmyzoneである要素を更新します。この種のインタラクションはAjaxと呼ばれ、非常にインタラクティブなWebアプリケーションのなか心です。Wikipedia(<a href="http://en.wikipedia.org/wiki/AJAX">http://en.wikipedia.org/wiki/AJAX</a>)ではつぎのように説明されています:</p>

<p>舞台裏のサーバーで小さな量のデータを交換することで、AjaxはWebページをより反応性の高いものにするのでユーザーが変更をするたびに全体のWebページをリロードする必要がありません。これはWebページのインタラクティビティ、スピードとユーザービリティを増大させることを意味します。</p>

<p>Ajaxは<code>XMLHttpRequest</code>に依存します。<code>XMLHttpRequest</code>は<code>hidden</code>フレームのように振る舞うJavaScriptのオブジェクトで、サーバーリクエストとWebページの残りの部分の操作からこのオブジェクトを更新できます。このオブジェクトはとても低いレベルで、異なるブラウザーが異なる方法で処理するので、通常はAjaxリクエストの処理を手作業で行うことは長い部分のコードを書くことを意味します。幸いにして、PrototypeはAjaxを処理するすべてのコードをカプセル化し、よりシンプルなAjaxオブジェクトを提供するので、symfonyはこのオブジェクトを頼りにします。いったんAjaxヘルパーをテンプレートのなかで使うとPrototypeライブラリが自動的にロードされるのはそういうわけです。</p>

<blockquote class="caution"><p>
  リモートアクションのURLが現在のページが同じドメインに所属しない場合Ajaxヘルパーは機能しません。この制限はセキュリティの理由のために存在し、回避できないブラウザーの制限に依存します。</p>
</blockquote>

<p>Ajaxのインタラクションは3つの部分から構成されます: コーラー(リンク、ボタン、フォーム、もしくはアクションを立ち上げるためにユーザーが操作するコントロール機能)、サーバーアクション、アクションのレスポンスを表示するページの領域です。リモートアクションがクライアントサイド上のJavaScript関数によって処理されるデータを返す場合、もっと複雑なインタラクションを開発できます。symfonyはAjaxのインタラクションを、すべてが<code>remote</code>を名前に含む、テンプレートに挿入するために複数のヘルパーを提供します。これらは共通の構文も共有します。構文はすべてのAjaxパラメーターを持つ連想配列です。AjaxヘルパーはJavaScriptではなくHTMLコードを出力することに注意してください。</p>

<blockquote class="sidebar"><p class="title">
  <strong>Aaxアクションはいかが？</strong></p>
  
  <p>リモート関数と呼ばれるアクションは通常のアクションです。これらはルーティングに従い、<code>return</code>をともなうレスポンスをレンダリングするためにビューを決定し、変数をテンプレートに渡し、ほかのアクションと同様にモデルを変更することができます。</p>
  
  <p>しかしながら、Ajaxを通して呼び出されたとき、アクションは<code>true</code>をつぎの呼び出しに対して返します:</p>

<pre class="php"><span class="re0">$isAjax</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequest</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">isXmlHttpRequest</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
  
  <p>symfonyはアクションがAjaxの文脈のなかにあることを知っており、それに応じてレスポンスに処理を適合させることができます。そのために、デフォルトで、Ajaxのアクションは開発環境ではWebデバッグツールバーを含みません。また、これらはデコレーションプロセスをスキップします(これらのテンプレートはデフォルトでレイアウトに含まれません)。デコレートされたAjaxのビューが欲しい場合、<code>view.yml</code>モジュールのファイルのなかでこのビューに対してhas_layout: true`を明示的に指定する必要があります。</p>
  
  <p>もう1つだけ言っておきます: Ajaxのインタラクションにおいて応答性は重大なので、レスポンスがあまり複雑ではない場合、ビューを作成することは避け、代わりにアクションから直接レスポンスを返すことはよいアイディアかもしれません。ですのでテンプレートをスキップしてAjaxのリクエストを加速するためにアクションのなかで<code>renderText()</code>メソッドを使うことができます。</p>
</blockquote>

<a name="ajax.link" id="ajax.link"></a><h3>Ajaxのリンク</h3>

<p>AjaxのリンクはWeb 2.0のアプリケーションで利用できるAjaxのインタラクションを広く共有します。<code>link_to_remote()</code>ヘルパーは、予想どおり、リモート機能を呼び出すリンクを出力します。リスト11-9で示されるように構文は<code>link_to()</code>のものととても似ています(2番目のパラメーターがAjaxオプションの連想配列であること以外)。</p>

<p>リスト11-9 - <code>link_to_remote()</code>ヘルパーによるAjaxリンク</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span> <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>この例では、<code>'この投稿を削除する'</code>のリンクをクリックするとバックグランドのなかで<code>post/delete</code>アクションへの呼び出しが行われます。サーバーによって返されたレスポンスは<code>id</code>が<code>feedback</code>である要素のなかに現れます。このプロセスは図11-1で説明されます。</p>

<p>図11-1 - ハイパーリンクでリモートの更新を実行する</p>

<p><img src="images/F1101.png" alt="ハイパーリンクでリモート更新を実行する" title="ハイパーリンクでリモートの更新を実行する" /></p>

<p>リスト11-10で示されるように、文字列の代わりに画像を使い、内部の<code>module/action</code>のURLの代わりにルール名を使い、オプションを3番目の引数の<code>&lt;a&gt;</code>タグに追加することができます。</p>

<p>リスト11-10 - <code>link_to_remote()</code>ヘルパーのオプション</p>

<pre class="php">&lt;div id=&quot;emails&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span>image_tag<span class="br0">&#40;</span><span class="st_h">'refresh'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span> <span class="sy0">=&gt;</span> <span class="st_h">'emails'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'@list_emails'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'class'</span>  <span class="sy0">=&gt;</span> <span class="st_h">'ajax_link'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<a name="ajaxdriven.forms" id="ajaxdriven.forms"></a><h3>Ajax駆動のフォーム</h3>

<p>Webフォームはよく別のアクションを呼び出しますが、これによってページ全体がリフレッシュされます。このフォームに対して<code>link_to_function()</code>が対応するものはサーバーのレスポンスをともなうページの要素だけを更新するフォーム投稿になります。これは<code>form_remote_tag()</code>ヘルパーが行うことで、構文はリスト11-11で示されます。</p>

<p>リスト11-11 - <code>form_remote_tag()</code>ヘルパーをともなうAjaxフォーム</p>

<pre class="php">&lt;div id=&quot;item_list&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_remote_tag<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'item_list'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'item/add'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;label for=&quot;item&quot;&gt;Item:&lt;/label&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'item'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="st_h">'Add'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p><code>form_remote_tag()</code>は通常の<code>form_tag()</code>ヘルパーのように<code>&lt;form&gt;</code>を開きます。このフォームを投稿することで、<code>item</code>フィールドをリクエストパラメーターとして、バックグラウンドでPOSTリクエストを<code>item/add</code>アクションに行います。リスト11-2で描かれているように、レスポンスは<code>item_list</code>要素の内容を置き換えます。通常の<code>&lt;/form&gt;</code>閉じタグでAjaxフォームを閉じてください。</p>

<p>図11-2 - リモート更新をフォームで実行する</p>

<p><img src="images/F1102.png" alt="フォームでリモート更新を実行する" title="フォームでリモート更新を実行する" /></p>

<blockquote class="caution"><p>
  Ajaxのフォームはmultipartになることはできません。これは<code>XMLHttpRequest</code>オブジェクトの制限です。このことはAjaxフォームを通してファイルのアップロードを処理できないことを意味します。しかしながら、次善策があります。たとえば、<code>XMLHttpRequest</code>の代わりに隠し<code>iframe</code>を使うことです。</p>
</blockquote>

<p>ページモードとAjaxモードの両方でフォームが機能するようにしたい場合、最前の解決方法はフォームを通常のものと同じように定義することです。しかしながらそのためには、通常の投稿ボタンに加えて、Ajaxでフォームを投稿する2番目のボタン(<code>&lt;input type="button"/&gt;</code>)が必要です。symfonyはこのボタンを<code>submit_to_remote()</code>と呼びます。これはグレースルフルデグラデーションを行うAjaxのインタラクションを開発するための助けになります。リスト11-12で例をご覧ください。</p>

<p>リスト11-12 - 通常の投稿とAjaxの投稿によるフォーム</p>

<pre class="php">&lt;div id=&quot;item_list&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'@item_add_regular'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;label for=&quot;item&quot;&gt;Item:&lt;/label&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'item'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> if_javascript<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_to_remote<span class="br0">&#40;</span><span class="st_h">'ajax_submit'</span><span class="sy0">,</span> <span class="st_h">'Add in Ajax'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
        <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'item_list'</span><span class="sy0">,</span>
        <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'@item_add'</span><span class="sy0">,</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> end_if_javascript<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
  &lt;noscript&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="st_h">'Add'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;/noscript&gt;
&lt;/form&gt;</pre>

<p>リモート投稿タグと通常の投稿タグを結びつけた使いかたの別の例は記事を編集するフォームです。これはAjaxのプレビューボタンと通常の投稿を行う投稿ボタンを提供します。</p>

<blockquote class="note"><p>
  ユーザーがEnterキーを押すとき、フォームはメインの<code>&lt;form&gt;</code>タグで定義されたアクションを使用して投稿されます。この例では通常のアクションです。</p>
</blockquote>

<p>モダンなフォームは投稿されたときだけでなく、フィールドの値がユーザーによって更新されたときも反応します。symfonyでは、そのために<code>observe_field()</code>ヘルパーを使うことができます。リスト11-13は提案機能を開発するためにこのヘルパーを使う例を示しています: <code>item</code>フィールドに入力されたそれぞれの文字はページの<code>item_suggestion</code>要素をリフレッシュするAjax呼び出しを呼び出します。</p>

<p>リスト11-13 - フィールドの値を<code>observe_field()</code>で変更するときにリモート関数を呼び出す</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'@item_add_regular'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;label for=&quot;item&quot;&gt;Item:&lt;/label&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'item'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;div id=&quot;item_suggestion&quot;&gt;&lt;/div&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> observe_field<span class="br0">&#40;</span><span class="st_h">'item'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
      <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'item_suggestion'</span><span class="sy0">,</span>
      <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'@item_being_typed'</span><span class="sy0">,</span>
  <span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="st_h">'Add'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p><code>@item_being_typed</code>ルールで書かれたモジュール/アクションはフォームを投稿しなくてもユーザーがobservedフィールド(<code>item</code>)の値を変更するたびに呼び出されます。アクションは<code>value</code>リクエストパラメーターから現在の<code>item</code>の値を取得することができます。observedフィールドの値以外のほかのものを渡したい場合、渡したいものを<code>with</code>パラメーターのなかのJavaScriptの表記として指定できます。たとえば、<code>param</code>パラメーターを取得するアクションが欲しい場合、リスト11-14で示されるように、<code>observe_field()</code>ヘルパーを書いてください。</p>

<p>リスト11-14 - 独自のパラメーターを<code>with</code>オプションでリモートアクションに渡す</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> observe_field<span class="br0">&#40;</span><span class="st_h">'item'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'item_suggestion'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'@item_being_typed'</span><span class="sy0">,</span>
    <span class="st_h">'with'</span>     <span class="sy0">=&gt;</span> <span class="st0">&quot;'param=' + value&quot;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>このヘルパーはHTML要素の出力を行わず、代わりにパラメーターとして渡された要素のためのふるまいを出力します。この章の後のほうでふるまいを割り当てるJavaScriptヘルパーの例をより多く見ることになります。</p>

<p>フォームのフィールドのすべてを観測したい場合、<code>observe_form</code>ヘルパーを使うべきです。フォームフィールドの1つが修正されるたびにこのヘルパーはリモート関数を呼び出します。</p>

<a name="periodically.calling.remote.functions" id="periodically.calling.remote.functions"></a><h3>定期的にリモート関数を呼び出す</h3>

<p>大事なことを言い忘れましたが、<code>periodically_call_remote()</code>ヘルパーは数秒毎に実行されるAjaxのインタラクションです。これはHTMLのコントロールに添付されませんが、全体のページのふるまいとして、バックグランドで透過的に実行されます。これはマウスの位置を追跡する、ラージテキストエリアの内容を自動保存するなどのために非常に便利です。リスト11-15はこのヘルパーの使いかたの例を示しています。</p>

<p>リスト11-15 - <code>periodically_call_remote()</code>で周期的にリモート関数を呼び出す</p>

<pre class="php">&lt;div id=&quot;notification&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> periodically_call_remote<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'frequency'</span> <span class="sy0">=&gt;</span> <span class="nu0">60</span><span class="sy0">,</span>
    <span class="st_h">'update'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'notification'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>       <span class="sy0">=&gt;</span> <span class="st_h">'@watch'</span><span class="sy0">,</span>
    <span class="st_h">'with'</span>      <span class="sy0">=&gt;</span> <span class="st0">&quot;'param=' + <span class="es1">\$</span>F('mycontent')&quot;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>リモート関数への2つの呼び出しを待つ秒数(<code>frequency</code>)を指定しない場合、デフォルト値の10秒が使われます。<code>with</code>パラメーターはJavaScriptで評価されるので、<code>$F()</code>関数といった、Prototypeの関数を使うことができます。</p>

<a name="remote.call.parameters" id="remote.call.parameters"></a><h2>リモート呼び出しパラメーター</h2>

<p>以前のセクションで説明されたすべてのAjaxヘルパーは、<code>update</code>パラメーターと<code>url</code>パラメーターに加えて、ほかの値を取ることができます。Ajaxパラメーターの連想配列はリモート呼び出しとそれらのレスポンスの処理のふるまいを変更し調整することができます。</p>

<a name="updating.distinct.elements.according.to.the.response.status" id="updating.distinct.elements.according.to.the.response.status"></a><h3>レスポンスの状態にしたがって異なる要素を更新する</h3>

<p>リモートアクションが失敗した場合、リモートヘルパーは、成功したレスポンスによって更新された要素以外の、別の要素の更新を選択できます。この目的のために、<code>update</code>パラメーターの値を連想配列に分割し、<code>success</code>と<code>failure</code>の場合に更新する要素に対して異なる値を設定します。たとえば1つのページと1つのエラーのフィードバックの領域内にたくさんのAjaxのインタラクションが存在する場合、これは大いに役立ちます。リスト11-16は条件つきの更新の扱いかたのお手本を示しています。</p>

<p>リスト11-16 - 条件つきの更新を扱う</p>

<pre class="php">&lt;div id=&quot;error&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
&lt;p&gt;Hello, World!&lt;/p&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'success'</span> <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span> <span class="st_h">'failure'</span> <span class="sy0">=&gt;</span> <span class="st_h">'error'</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<blockquote class="tip"><p>
  HTTPのエラーコード(500、404と2XXの範囲にないすべてのコード)は、<code>sfView::ERROR</code>を返すアクションではなく、failureの場合の更新を実行します。Ajaxのfailureを返すアクションを作りたい場合、アクションは<code>$this-&gt;getResponse()-&gt;setStatusCode(404)</code>もしくは似たようなものを呼び出さなければなりません。</p>
</blockquote>

<a name="updating.an.element.according.to.position" id="updating.an.element.according.to.position"></a><h3>位置にしたがって要素を更新する</h3>

<p><code>update_element_function()</code>ヘルパーと同様に、<code>position</code>パラメーターを追加することで特定の要素に相対的なものとして更新する要素を指定できます。リスト11-17は例を示しています。</p>

<p>リスト11-17 - レスポンスの位置を変更するために<code>position</code>パラメーターを使う</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
&lt;p&gt;Hello, World!&lt;/p&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'position'</span> <span class="sy0">=&gt;</span> <span class="st_h">'after'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>これは<code>feedback</code>要素の後にAjax呼び出しのレスポンスを挿入することができます; すなわち、<code>&lt;div&gt;</code>と<code>&lt;p&gt;</code>のあいだです。このメソッドによって、いくつかのAjax呼び出しを行い、<code>update</code>要素のあとで累積するレスポンスを見ることができます。</p>

<p><code>position</code>パラメーターはつぎの値を取ることができます:</p>

<ul>
<li><code>before</code>: 要素の前</li>
<li><code>after</code>: 要素の後</li>
<li><code>top</code>: 要素の内容の一番上</li>
<li><code>bottom</code>: 要素の内容の一番下</li>
</ul>

<a name="updating.an.element.according.to.a.condition" id="updating.an.element.according.to.a.condition"></a><h3>条件にしたがって要素を更新する</h3>

<p>リスト11-18で示されるように、リモート呼び出しは、<code>XMLHttpRequest</code>を実際に投稿するまえに、ユーザーが確認できるようにする追加パラメーターを取ることができます。</p>

<p>リスト11-18 - リモート関数を呼び出すまえに確認を求める<code>confirm</code>パラメーターを使う</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'confirm'</span>  <span class="sy0">=&gt;</span> <span class="st_h">'よろしいですか？'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>"よろしいですか？"を示すJavaScriptのダイアログボックスはユーザーがリンクをクリックしたときにポップアップを行い、<code>post/delete</code>アクションはユーザーがOKをクリックして選択を確認する場合だけに呼び出されます。</p>

<p>リスト11-19で示されるように、<code>condition</code>パラメーターを提供した場合、リモート呼び出しはブラウザーサイド(JavaScript)で実行されるテストによって調整されます。</p>

<p>リスト11-19 - クライアントサイドのテストにしたがって条件つきでリモート関数を呼び出す</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>       <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'condition'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;$('elementID') == true&quot;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<a name="determining.the.ajax.request.method" id="determining.the.ajax.request.method"></a><h3>Ajaxのリクエストメソッドを決定する</h3>

<p>デフォルトでは、AjaxのリクエストはPOSTメソッドで構成されます。データを修正しないAjaxの呼び出しを行いたい場合、もしくはAjaxの呼び出しの結果として組み込みのバリデーションを持つフォームを表示したい場合、GETするAjaxのリクエストメソッドを変更することが必要な場合があります。リスト11-20で示されるように、メソッドオプションはAjaxのリクエストを変更します。</p>

<p>リスト11-20 - Ajaxのリクエストメソッドを変更する</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>       <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'method'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'get'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<a name="authorizing.script.execution" id="authorizing.script.execution"></a><h3>スクリプトの実行を許可する</h3>

<p>Ajaxの呼び出しのレスポンスコード(<code>update</code>要素に挿入され、サーバーによって送られてきたコード)がJavaScriptを含む場合、デフォルトでこれらのスクリプトが実行されないことに驚くかもしれません。これはリモート攻撃のリスクを減らし開発者がレスポンス内に存在するコードを確実に知っているときのみスクリプトの実行を可能にすることが目的です。</p>

<p>リモートレスポンスのなかでスクリプトの実行を行う機能を<code>script</code>オプションによって明確に宣言する必要があるのはそういうわけです。リスト11-21はリモートレスポンスから実行できるJavaScriptを宣言するAjaxの呼び出しの例を示しています。</p>

<p>リスト11-21 - Ajaxのレスポンスでスクリプトの実行を許可する</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span>
  <span class="co1">// post/deleteアクションのレスポンスがJavaScriptを含む場合、</span>
  <span class="co1">// ブラウザーで実行されることを許可する</span>
  <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span> <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'script'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>リモートテンプレートが(<code>remote_function()</code>といった)Ajaxヘルパーを含む場合、これらのPHP関数はJavaScriptのコードを生成し、<code>'script' =&gt; true</code>オプションを追加しないかぎりこれらは実行されないことに注意してください。</p>

<blockquote class="note"><p>
  リモートレスポンスに対してスクリプトの実行を有効にしても、生成したコードをチェックするツールを使わないのであれば、リモートコードでコードを実際に見ることはありません。スクリプトは実行されますが、コードには現れません、奇妙なことかもしれませんが、このふるまいは完全に普通です。</p>
</blockquote>

<a name="creating.callbacks" id="creating.callbacks"></a><h3>コールバック機能を作成する</h3>

<p>Ajaxのインタラクションの重大な欠点は更新する領域が実際に更新されるまでユーザーには見えないことです。遅いネットワーク、もしくはサーバー障害の場合、実際は処理されなかったにもかかわらず、ユーザーは自分のアクションが反映されたと信じるかもしれません。Ajaxのインタラクションでユーザーのイベントを通知することが重要であるのはそういうわけです。</p>

<p>デフォルトでは、さまざまなJavaScriptのコールバックが(進行インディケータなどに対して)起動される間それぞれのリモートリクエストは非同期プロセスです。すべてのコールバックは<code>request</code>オブジェクトにアクセスできます。<code>request</code>オブジェクトは<code>XMLHtppRequest</code>を保持します。コールバックはAjaxのインタラクションのイベントに対応します:</p>

<ul>
<li><code>before</code>: リクエストが初期化される前</li>
<li><code>after</code>: リクエストが初期化された直あとでロードされる前</li>
<li><code>loading</code>: リモートレスポンスがブラウザーによってロードされているとき</li>
<li><code>loaded</code>: ブラウザーがリモートレスポンスをロードすることをを終わらせたとき</li>
<li><code>interactive</code>: ロードが終了していなくても、ユーザーがリモートレスポンスと相互作用するとき</li>
<li><code>success</code>: <code>XMLHttpRequest</code>が完結し、HTTPステータスコードが2XXの範囲にあるとき</li>
<li><code>failure</code>: <code>XMLHttpRequest</code>が完結し、HTTPステータスコードが2XXの範囲にないとき</li>
<li><code>404</code>: リクエストが404ステータスを返すとき</li>
<li><code>complete</code>: <code>XMLHttpRequest</code>が完結したとき(それらが存在する場合、success<code>もしくは</code>failure`のあとで起動します)</li>
</ul>

<p>たとえば、リモート呼び出しが初期化されレスポンスが一度受信されたとき、これを隠すために、ローディングインディケータを表示することはよくあることです。これを実現するには、リスト11-22で示されるように、<code>loading</code>と<code>complete</code>パラメーターをAjaxの呼び出しに追加します。</p>

<p>リスト11-22 - アクティビティインディケータの表示と隠匿を行うためにAjaxのコールバックを使う</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;indicator&quot;&gt;読み込み中...&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'loading'</span>  <span class="sy0">=&gt;</span> <span class="st0">&quot;Element.show('indicator')&quot;</span><span class="sy0">,</span>
    <span class="st_h">'complete'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;Element.hide('indicator')&quot;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p><code>show</code>メソッドと<code>hide</code>メソッドは、JavaScriptのElementオブジェクトと同様に、Prototypeのそのほかの便利な追加機能です。</p>

<a name="creating.visual.effects" id="creating.visual.effects"></a><h2>視覚効果を作成する</h2>

<p>Webページで<code>&lt;div&gt;</code>要素を表示したり隠したりする以上のことをできるようにするために、symfonyはscript.aculo.usのライブラリの視覚効果を統合します。視覚効果の構文は<a href="http://script.aculo.us/">http://script.aculo.us/</a>のwikiでよいドキュメントが見つかります。基本的には、script.aculo.usのライブラリは複雑な視覚効果を実現するためにDOMを操作するJavaScriptのオブジェクトと関数を提供します。リスト11-23でいくつかの例をご覧ください。結果はWebページの特定領域上の視覚的なアニメーションなので、これらが実際に何をしているのかを理解するために自分で効果を確かめることをお勧めします。script.aclulo.usのWebサイトは動的な効果のアイディアを得ることができるギャラリーを提供します。</p>

<p>リスト11-23 - Script.acuo.usによるJavaScriptの視覚効果</p>

<pre class="php"><span class="co1">// 'my_field'要素をハイライトする</span>
Effect<span class="sy0">.</span>Highlight<span class="br0">&#40;</span><span class="st_h">'my_field'</span><span class="sy0">,</span> <span class="br0">&#123;</span> startcolor<span class="sy0">:</span><span class="st_h">'#ff99ff'</span><span class="sy0">,</span> endcolor<span class="sy0">:</span><span class="st_h">'#999999'</span> <span class="br0">&#125;</span><span class="br0">&#41;</span>
&nbsp;
<span class="co1">// 要素をブラインドダウンする</span>
Effect<span class="sy0">.</span>BlindDown<span class="br0">&#40;</span><span class="st_h">'id_of_element'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="co1">// 要素をフェードアウェイする</span>
Effect<span class="sy0">.</span>Fade<span class="br0">&#40;</span><span class="st_h">'id_of_element'</span><span class="sy0">,</span> <span class="br0">&#123;</span> transition<span class="sy0">:</span> Effect<span class="sy0">.</span>Transitions<span class="sy0">.</span>wobble <span class="br0">&#125;</span><span class="br0">&#41;</span></pre>

<p>symfonyは、<code>Javascript</code>ヘルパーグループの一部でもある、<code>visual_effect()</code>ヘルパーで<code>JavaScriptの</code>Effect`オブジェクトをカプセル化します。リスト11-24で示されるように、このヘルパーは通常のリンクで使えるJavaScriptを出力します。</p>

<p>リスト11-24 <code>visual_effect()</code>ヘルパーによるテンプレートでの視覚効果</p>

<pre class="php">&lt;div id=&quot;secret_div&quot; style=&quot;display:none&quot;&gt;最初からずっと存在していました！&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_function<span class="br0">&#40;</span>
  <span class="st_h">'秘密のdivを表示する'</span><span class="sy0">,</span>
  visual_effect<span class="br0">&#40;</span><span class="st_h">'appear'</span><span class="sy0">,</span> <span class="st_h">'secret_div'</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
// はEffect.Appear('secret_div')への呼び出しを行う</pre>

<p>リスト11-25で示されるように、<code>visual_effects()</code>ヘルパーはAjaxのコールバックでも利用できます。このヘルパーはリスト11-22のようなアクティビティインディケータを表示しますが、視覚的にはより満足のゆくものです。<code>indicator</code>要素はAjaxの呼び出しが始まるときに次第に表示され、レスポンスが到達したときに次第に消えます。加えて、<code>feedback</code>要素は、ユーザーの注目をこの部分のウィンドウに引きつけるために、リモート呼び出しによって更新されていた後にハイライトされます。</p>

<p>リスト11-25 - Ajaxのコールバックにおける視覚効果</p>

<pre class="php">&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;indicator&quot; style=&quot;display: none&quot;&gt;ロード中...&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'この投稿を削除する'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'update'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
    <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'post/delete?id='</span><span class="sy0">.</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'loading'</span>  <span class="sy0">=&gt;</span> visual_effect<span class="br0">&#40;</span><span class="st_h">'appear'</span><span class="sy0">,</span> <span class="st_h">'indicator'</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="st_h">'complete'</span> <span class="sy0">=&gt;</span> visual_effect<span class="br0">&#40;</span><span class="st_h">'fade'</span><span class="sy0">,</span> <span class="st_h">'indicator'</span><span class="br0">&#41;</span><span class="sy0">.</span>
                  visual_effect<span class="br0">&#40;</span><span class="st_h">'highlight'</span><span class="sy0">,</span> <span class="st_h">'feedback'</span><span class="br0">&#41;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>コールバックのなかで視覚効果を連結することでこれらを結びつける方法に注目してください。</p>

<a name="json" id="json"></a><h2>JSON</h2>

<p>JSON(JavaScript Object Notation)は軽量のデータ交換フォーマットです。基本的には、オブジェクトの情報を運ぶJavaScriptのハッシュ(リスト11-26の例を参照)にすぎません。しかし、JSONはAjaxのインタラクションに対して2つのすばらしい利点があります: JavaScriptのなかで読みやすく、Webレスポンスのサイズを減らすことができます。</p>

<p>リスト11-26 - JavaScriptのなかのサンプルのJSONオブジェクト</p>

<pre><code>var myJsonData = {"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}
</code></pre>

<p>AjaxのアクションがさらなるJavaScriptの処理に対してコーラー(caller)のページへ構造化データを返す必要がある場合、JSONはレスポンスのためのよいフォーマットです。たとえば、1つのAjaxの呼び出しがコーラーのページでいくつかの要素を更新する場合において非常に便利です。</p>

<p>たとえば、リスト11-27のようなコーラーのページを想像してください。このページは更新することが必要かもしれない2つの要素を持ちます。1つのリモートヘルパーは、ページの要素の両方ではなく片方(<code>title</code>もしくは<code>name</code>)だけを更新できます。</p>

<p>リスト11-27 - 複数のAjaxを更新するためのサンプルのテンプレート</p>

<pre class="php"><span class="sy0">&lt;</span>h1 id<span class="sy0">=</span><span class="st0">&quot;title&quot;</span><span class="sy0">&gt;</span>基本的な手紙<span class="sy0">&lt;/</span>h1<span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>p<span class="sy0">&gt;</span>親愛なる<span class="sy0">&lt;</span>span id<span class="sy0">=</span><span class="st0">&quot;name&quot;</span><span class="sy0">&gt;</span>name_here<span class="sy0">&lt;/</span>span<span class="sy0">&gt;</span>へ、<span class="sy0">&lt;/</span>p<span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>p<span class="sy0">&gt;</span>あなたのEメールは受信され近いうちに返信されます。<span class="sy0">&lt;/</span>p<span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>p<span class="sy0">&gt;</span>Sincerely<span class="sy0">,&lt;/</span>p<span class="sy0">&gt;</span></pre>

<p>両方を更新するために、Ajaxのレスポンスがつぎの配列を含むJSONのヘッダーになることができるか想像してください:</p>

<pre><code> [["title", "My basic letter"], ["name", "Mr Brown"]]
</code></pre>

<p>それからリモート呼び出しは、JavaScriptのちょっとした助けによって、簡単にこのレスポンスを解釈し、列のなかのフィールドを更新できます。リスト11-28のコードはこの効果を得るためにリスト11-27のテンプレートに追加できるものを示しています。</p>

<p>リスト11-28 - リモートレスポンスから複数の要素を更新する</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_remote<span class="br0">&#40;</span><span class="st_h">'文字列をリフレッシュする'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'url'</span>      <span class="sy0">=&gt;</span> <span class="st_h">'publishing/refresh'</span><span class="sy0">,</span>
  <span class="st_h">'complete'</span> <span class="sy0">=&gt;</span> <span class="st_h">'updateJSON(request, json)'</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_tag<span class="br0">&#40;</span><span class="st0">&quot;
function updateJSON(request, json)
{
  var nbElementsInResponse = json.length;
  for (var i = 0; i &lt; nbElementsInResponse; i++)
  {
     Element.update(json[i][0], json[i][1]);
  }
}
&quot;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p><code>complete</code>コールバックはレスポンスの<code>json</code>ヘッダーにアクセス可能でこれをサードパーティの関数に渡すことができます。このカスタム<code>updateJSON()</code>関数はJSONヘッダーのイテレーションを行い、それぞれの配列のメンバーに対して、<code>second</code>パラメーターの内容を持つ最初のパラメーターによって名づけられた要素を更新します。</p>

<p>リスト11-29は<code>publishing/refresh</code>アクションがJSONのレスポンスを返す方法を示してます。</p>

<p>リスト11-29 - JSONのヘッダーを返すサンプルのアクション</p>

<pre class="php"><span class="kw2">class</span> publishingActions <span class="kw2">extends</span> sfActions
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeRefresh<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$output</span> <span class="sy0">=</span> <span class="st_h">'[[&quot;title&quot;, &quot;基本的な手紙&quot;], [&quot;name&quot;, &quot;ブラウンさん &quot;]]'</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">setHttpHeader</span><span class="br0">&#40;</span><span class="st0">&quot;X-JSON&quot;</span><span class="sy0">,</span> <span class="st_h">'('</span><span class="sy0">.</span><span class="re0">$output</span><span class="sy0">.</span><span class="st_h">')'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">return</span> sfView<span class="sy0">::</span><span class="me2">HEADER_ONLY</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre>

<p>HTTPプロトコルはJSONをレスポンスヘッダーに保存することを許可します。レスポンスは内容を持たないので、アクションはこれをヘッダーのみとして即座に送ります。これはビューレイヤーを完全に回避し、<code>renderText()</code>と同じぐらい速いですが、より小さなレスポンスをともないます。</p>

<blockquote class="caution"><p>
  リスト11-29で示されるアプローチにはいくつかの制限があります: HTTPヘッダーの最大サイズです。公式の制限はありませんが、大きなヘッダーは十分に転送されないもしくはブラウザーによって解釈されないことがあります。このことは、JSONの配列が大きい場合、リモートアクションは、JavaScript配列としてJSONを持つ、通常のレスポンスを返すことを意味します。</p>
</blockquote>

<p>JSONはWebアプリケーションのあいだで標準規格となりました。Webサービスは、サーバーよりもクライアント上でのサービスの統合(マッシュアップ)を可能にするために、XMLよりもJSON形式のレスポンスをよく提示します。サーバーとJavaScript関数の間のコミュニケーションのためにどちらのフォーマットを使うべきか悩んでいる場合、おそらくJSONはあなたの最善の方法です。</p>

<blockquote class="tip"><p>
  バージョン5.2以降、PHPは<code>json_encode()</code>と<code>json_decode()</code>の2つの関数を提供します。これらによってPHPとJSONの構文のあいだで配列を変換できるようになります。逆もしかりです(<a href="http://www.php.net/manual/ref.json.php">http://www.php.net/manual/ref.json.php</a>)。これらは一般的なJSON配列とAjaxの統合を円滑にします。</p>
</blockquote>

<a name="performing.complex.interactions.with.ajax" id="performing.complex.interactions.with.ajax"></a><h2>複雑なインタラクションをAjaxで実行する</h2>

<p>symfonyのAjaxヘルパーのなかには、単独の呼び出しで複雑なインタラクションを組み立てるいくつかのツールも見つかります。これらのツールによって複雑なJavaScriptのコードをともなわずにデスクトップのアプリケーションのようなインタラクション(ドラッグドロップ、オートコンプリート、ライブ編集)によってユーザーエクスペリエンスを強化できます。つぎのセクションでは複雑なインタラクションのためのヘルパーを説明し、シンプルな例を示します。追加パラメーターと調整方法はscript.aculo.usのドキュメントで説明されます。</p>

<blockquote class="caution"><p>
  複雑なインタラクションが可能であれば、これらが自然に感じられるように調整を行うプレゼンテーションのための追加時間が必要です。これらがユーザーエクスペリエンスを強化することを確信するときのみこれらをご利用ください。これらがユーザーを混乱させるリスクが存在するのであればこれらを避けてください。</p>
</blockquote>

<a name="autocompletion" id="autocompletion"></a><h3>オートコンプリート</h3>

<p>ユーザーが入力している間にユーザーのエントリーをマッチする単語のリストを表示するテキスト入力コンポーネントはオートコンプリート(autocompletetion)と呼ばれます。<code>input_auto_complete_tag()</code>と呼ばれる単独のヘルパーによって、リモートアクションがリスト11-30で示された例と似たようなHTMLのアイテムとしてフォーマットされたレスポンスを返す条件の下で、この効果を実現できます。</p>

<p>リスト11-30 - オートコンプリートのタグと互換性のあるレスポンスの例</p>

<pre><code>&lt;ul&gt;
  &lt;li&gt;suggestion1&lt;/li&gt;
  &lt;li&gt;suggestion2&lt;/li&gt;
  ...
&lt;/ul&gt;
</code></pre>

<p>リスト11-31で示されているつぎの例のように、通常のテキスト入力を処理するようにヘルパーをテンプレートのなかに挿入してください。</p>

<p>リスト11-31 - テンプレートのなかでオートコンプリートタグヘルパーを使う</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'mymodule/myaction'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  筆者の名前を見つける:
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_auto_complete_tag<span class="br0">&#40;</span><span class="st_h">'author'</span><span class="sy0">,</span> <span class="st_h">'default name'</span><span class="sy0">,</span>
    <span class="st_h">'author/autocomplete'</span><span class="sy0">,</span>
    <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'autocomplete'</span> <span class="sy0">=&gt;</span> <span class="st_h">'off'</span><span class="br0">&#41;</span><span class="sy0">,</span>
    <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'use_style'</span>    <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="st_h">'Find'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p>ユーザーが<code>author</code>フィールドに文字を入力するたびにこれは<code>author/autocomplete</code>アクションを呼び出します。アクションが<code>author</code>のリクエストパラメーターにしたがって可能なマッチのリストを決定し、リスト11-30と同じようなフォーマットでこれらを返すように設計するのはあなた次第です。図11-3で示されるように、ヘルパーは<code>author</code>タグの下でリストを表示し、提示された項目の1つをクリックする、もしくはキーボードで選択すると入力が補完されます。</p>

<p>図11-3 - オートコンプリートの例</p>

<p><img src="images/F1103.png" alt="オートコンプリートの例" title="オートコンプリートの例" /></p>

<p><code>input_auto_complete_tag()</code>ヘルパーの3番目の引数はつぎのパラメーターを取ることができます:</p>

<ul>
<li><code>use_style</code>: レスポンスが自動的に一覧を表示するスタイル。</li>
<li><code>frequency</code>: 周期的な呼び出しの頻度(デフォルトは0.4秒)。</li>
<li><code>indicator</code>: オートコンプリートのローディングが始まり完了した場合に消えるときに表示されるインディケータのid。</li>
<li>tokens: トークン化されたインクリメンタルなオートコンプリートを許可するため。たとえば、このパラメーターを<code>,</code>に設定してユーザーが<code>jane, george</code>を入力すると、アクションは<code>'george'</code>の値だけを受けとります。</li>
</ul>

<a name="draganddrop" id="draganddrop"></a><h3>ドラッグアンドドロップ</h3>

<p>要素をマウスで掴む、動かす、どこかで放すといった機能はデスクトップのアプリケーションでは親しまれていますが、Webブラウザーにおいてはまれです。無地のJavaScriptにおいてこのようなふるまいをコードに書く作業がとても非常に複雑だからです。幸いにして、symfonyにおいてこの機能を実現するには1行だけ必要です。</p>

<p>symfonyは<code>draggable_element()</code>と<code>drop_receiving_element()</code>の2つのヘルパーを提供します。これらをふるまいの修飾子としてみなすことができます; これらはオブザーバと機能をこれが扱う要素に追加します。ドラッグ可能な要素に対して要素をドラッグ可能な要素もしくは受けとる要素として宣言するためにこれらを使います。ドラッグ可能な要素はこれをマウスでクリックすることでつかみ取ることができます。マウスボタンが放されるまで、要素を動かす、もしくはウィンドウを越えてドラッグされます。`ドラッグ可能な要素が放されたとき、受けとる要素はリモート関数を呼び出します。リスト11-32は要素を受けとるショッピングカードとこのタイプのインタラクションのお手本を示しています。</p>

<p>リスト11-32 - ショッピングカートでドラッグ可能な要素とドロップを受けとる要素</p>

<pre class="php">&lt;ul id=&quot;items&quot;&gt;
  &lt;li id=&quot;item_1&quot; class=&quot;food&quot;&gt;にんじん&lt;/li&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> draggable_element<span class="br0">&#40;</span><span class="st_h">'item_1'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'revert'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;li id=&quot;item_2&quot; class=&quot;food&quot;&gt;りんご&lt;/li&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> draggable_element<span class="br0">&#40;</span><span class="st_h">'item_2'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'revert'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;li id=&quot;item_3&quot; class=&quot;food&quot;&gt;オレンジ&lt;/li&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> draggable_element<span class="br0">&#40;</span><span class="st_h">'item_3'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'revert'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/ul&gt;
&lt;div id=&quot;cart&quot;&gt;
  &lt;p&gt;カートが空です&lt;/p&gt;
  &lt;p&gt;ここにある品物をドラッグしてカートに追加してください&lt;/p&gt;
&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> drop_receiving_element<span class="br0">&#40;</span><span class="st_h">'cart'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'url'</span>        <span class="sy0">=&gt;</span> <span class="st_h">'cart/add'</span><span class="sy0">,</span>
  <span class="st_h">'accept'</span>     <span class="sy0">=&gt;</span> <span class="st_h">'food'</span><span class="sy0">,</span>
  <span class="st_h">'update'</span>     <span class="sy0">=&gt;</span> <span class="st_h">'cart'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>並べ替えをされていないリストのそれぞれの項目をマウスでつかみ取ることが可能で、ウィンドウを越えてドラッグされます。放されたとき、これらは元の位置に戻ります。<code>cart</code>要素を越えて放されたとき、<code>cart/add</code>アクションへのリモート呼び出しを発動させます。<code>id</code>リクエストパラメーターを見ることで、アクションはどの品物が<code>cart</code>要素にドロップされたのか決定できます。リスト11-32は本当のショッピングセッションをシミュレートしています: 品物をつかみとり、カートで放します。会計に進みます。</p>

<blockquote class="tip"><p>
  リスト11-32において、ヘルパーが修正する要素の直後にヘルパーが書かれますが、これは要件ではありません。テンプレートの終わりですべての<code>draggalbe_element()</code>と<code>drop_receiving_element()</code>ヘルパーをとても上手に分類できました。重要なことはヘルパー呼び出しの最初の引数で、これはふるまいを受けとる要素の識別子を指定します。</p>
</blockquote>

<p><code>draggable_element()</code>ヘルパーはつぎのパラメーターを受け入れます:</p>

<ul>
<li><code>revert</code>: <code>true</code>に設定した場合、要素は放されたときに元の場所に戻ります。ドラッグが終了したとき、任意の関数参照にもなり、呼び出されます。</li>
<li><code>ghosting</code>: 要素をクローンしてそのクローンをドラッグし、クローンがドロップされるまで、所定の位置に留めます。</li>
<li><code>snap</code>: <code>false</code>に設定した場合、スナッピングは起きません。さもなければ、<code>x</code>と<code>y</code>の間隔のグリッドの交点だけに<code>draggable</code>がドラッグされます。そしてこの場合、<code>xy</code>もしくは<code>[x,y]</code>もしくは<code>function(x,y){return [x,y]}</code>の形式をとります。</li>
</ul>

<p><code>drop_receiving_element()</code>ヘルパーはつぎのパラメーターを受けとります:</p>

<ul>
<li><code>accept</code>: 文字列もしくはCSSクラスを記述する文字列の配列。要素はこれらのCSSクラスを1つもしくは複数持つドラッグ可能な要素だけを受けとります。</li>
<li><code>hoverclass</code>: ドラッグ可能な受けとり要素をある要素の上にドラッグするときにその要素に追加されるCSSクラス</li>
</ul>

<a name="sortable.lists" id="sortable.lists"></a><h3>ソート可能なリスト</h3>

<p><code>draggable</code>要素によって提供されたほかの可能性はマウスで項目を動かすことでリストをソートする機能です。<code>sortable_element()</code>ヘルパーはソート可能なふるまいを項目に追加します。リスト11-33はこの機能を実装するよい例です。</p>

<p>リスト11-33 -ソート可能なリストの例</p>

<pre class="php">&lt;p&gt;何が一番好きですか？&lt;/p&gt;
&lt;ul id=&quot;order&quot;&gt;
  &lt;li id=&quot;item_1&quot; class=&quot;sortable&quot;&gt;にんじん&lt;/li&gt;
  &lt;li id=&quot;item_2&quot; class=&quot;sortable&quot;&gt;りんご&lt;/li&gt;
  &lt;li id=&quot;item_3&quot; class=&quot;sortable&quot;&gt;オレンジ&lt;/li&gt;
  // どのみち誰も芽キャベツが好きではない
  &lt;li id=&quot;item_4&quot;&gt;芽キャベツ&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> sortable_element<span class="br0">&#40;</span><span class="st_h">'order'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'url'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'item/sort'</span><span class="sy0">,</span>
  <span class="st_h">'update'</span> <span class="sy0">=&gt;</span> <span class="st_h">'feedback'</span><span class="sy0">,</span>
  <span class="st_h">'only'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'sortable'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p><code>sortable_element()</code>ヘルパーのマジックによって、<code>&lt;ul&gt;</code>要素はソート可能になります。このことはその子要素をドラッグアンドドロップで再び並べ替えることができることを意味します。リストを並べ替えるためにユーザーが項目をドラッグして放すたびに、Ajaxリクエストはつぎのパラメーターによって構成されます:</p>

<pre><code>POST /sf_sandbox/web/frontend_dev.php/item/sort HTTP/1.1
  order[]=1&amp;order[]=3&amp;order[]=2&amp;_=
</code></pre>

<p>十分に並べ替えられたリストは配列として渡されます(<code>orde[$rank]=$id</code>のフォーマットで、<code>$rank</code>は<code>0</code>で始まり、<code>$id</code>はリスト要素の<code>id</code>プロパティのアンダースコア(<code>_</code>)のあとで来るものに基づきます)。<code>id</code>プロパティのソート可能な要素(この例では<code>order</code>)はパラメーターの配列を名づけるために使われます。</p>

<p><code>sortable_element()</code>ヘルパーはつぎのパラメーターを受けとります:</p>

<ul>
<li><code>only</code>: CSSクラスを記述する文字列もしくは文字列の配列。このクラスをともなうsortable要素の子要素だけが動かせる。</li>
<li><code>hoverclass</code>: マウスが要素の上にホーバーされたときにその要素に追加されるCSSクラス。</li>
<li><code>overlap</code>: 項目がインラインに表示される場合は<code>horizontal</code>に設定、1行につき1つの項目があるとき(例の場合)、<code>vertical</code>に設定します。</li>
<li><code>tag</code>: リストの順序が<code>&lt;li&gt;</code>要素のセットではない場合、ドラッグ可能なものにするためにソート可能な子要素を決定しなければなりません(たとえば、<code>div</code>もしくは<code>dl</code>)。</li>
</ul>

<a name="edit.in.place" id="edit.in.place"></a><h3>その場で編集する</h3>

<p>より多くのWebアプリケーションは、フォームにおいて内容を再表示することなく、ページ上でユーザーがページの内容を直接編集することを許可しています。インタラクションの原則はシンプルであることです。テキストのブロックはユーザーがその上にマウスをホーバーするときにハイライトされます。ユーザーがブロックの内側でクリックする場合、プレーンテキストはブロックのテキストで入力されたテキストエリアに変換され、保存ボタンが表示されます。ユーザーはテキストエリアの内側でテキストを編集することが可能で、いったんそれを保存すると、テキストエリアとテキストはプレーンなフォームに表示されます。symfonyにおいて、<code>input_in_place_editor_tag()</code>ヘルパーによってこの編集可能なふるまいを要素に追加できます。リスト11-34はこのヘルパーの使いかたのお手本を示しています。</p>

<p>リスト11-34 - 編集可能なテキストの例</p>

<pre class="php">&lt;div id=&quot;edit_me&quot;&gt;このテキストを編集できます&lt;/div&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_in_place_editor_tag<span class="br0">&#40;</span><span class="st_h">'edit_me'</span><span class="sy0">,</span> <span class="st_h">'mymodule/myaction'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'cols'</span>        <span class="sy0">=&gt;</span> <span class="nu0">40</span><span class="sy0">,</span>
  <span class="st_h">'rows'</span>        <span class="sy0">=&gt;</span> <span class="nu0">10</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>ユーザーが編集可能なテキストをクリックしたとき、編集可能で、テキストで満たされたテキスト入力エリアによって置き換えられます。フォームが投稿されたとき、<code>mymodule/myaction</code>アクションは<code>value</code>パラメーターとしての編集された値のセットを伴ってAjaxのなかに呼び出されます。アクションの結果は編集可能な要素を更新します。これはとても速く書くことが可能でとても強力です。</p>

<p><code>input_in_place_editor_tag()</code>ヘルパーはつぎのパラメーターを受けとります:</p>

<ul>
<li><code>cols</code>と<code>rows</code>: 編集のために表示されるテキスト入力領域のサイズ(<code>rows</code>が1より大きい場合は<code>&lt;textarea&gt;</code>になります)</li>
<li><code>loadTextURL</code>: 編集するテキストを表示するために呼び出されるアクションのURIです。編集可能な要素が特別な整形方法を利用することかつユーザーが整形なしのテキストを編集できるようにしたい場合にこれは便利です。</li>
<li><code>save_text</code>と<code>cancel_text</code>: 保存リンク(デフォルトは"ok")とキャンセルリンク(デフォルトは"cancel")上のテキスト。</li>
</ul>

<a name="summary" id="summary"></a><h2>まとめ</h2>

<p>クライアントサイドのふるまいを手に入れるためにテンプレートのなかでJavaScriptを書くことに疲れましたら、JavaScriptヘルパーは代わりのシンプルな方法を提供します。これらのヘルパーは基本的なリンクのふるまいと要素の更新を自動化するだけでなく、すぐにAjaxのインタラクションを開発する方法も提供します。強力なPrototypeによる構文強化とscript.aculo.usによるすばらしい視覚効果の助けによって、複雑なインタラクションを実現するには、数行のコードを書くことだけが必要です。</p>

<p>高度にインタラクティブなアプリケーションはsymfonyで静的なページを作ることと同じぐらい簡単なので、ほとんどすべてのデスクトップアプリケーションのインタラクションはWebアプリケーションで利用できると考えることができます。</p>
</div>
<div class="navigation">
<hr/>
<table width="100%">
<tr>
<td width="40%" align="left"><a href="10-Forms.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="12-Caching.html">次の章</a></td>
</tr>
</table>

</div>
</body>

</html>
